package com.duoduo.common.jpa.service;

import java.lang.reflect.ParameterizedType;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import com.duoduo.common.core.exception.DuoException;
import com.duoduo.common.core.exception.ErrorCode;
import com.duoduo.common.core.util.Page;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import lombok.SneakyThrows;


public abstract class CommonService<T,E,ID>{
	
	public Class<T> t;
	
	public Class<E> e;
	
    @PersistenceContext
    EntityManager em;
    
	private SimpleJpaRepository<E, ID> simpleJpaRepository;
    
    @Autowired
    public void setSimpleJpaRepository(){
        simpleJpaRepository = new SimpleJpaRepository<E, ID>(getEClass(),em);
    }
	
	abstract public Specification<E> getWhere(final T dto);
	
	@SuppressWarnings("unchecked")
	public Class<T> getTClass() {
		  t = (Class<T>) ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	        return t;
	    }
	@SuppressWarnings("unchecked")
	public Class<E> getEClass() {
		  e = (Class<E>) ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
	        return e;
	    }
	public Page<T> page(Integer pageNum, Integer pageSize, T param) {
		PageRequest pageRequest = PageRequest.of(pageNum-1, pageSize);
		Specification<E> where = this.getWhere(param);
		org.springframework.data.domain.Page<T> pageData = simpleJpaRepository.findAll(where,pageRequest).map(p ->{
			 T targer;
			try {
				targer = this.getTClass().getDeclaredConstructor().newInstance();
				BeanUtils.copyProperties(p,targer);
				return targer;
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		});
		Page<T> page = new Page<T>();
		page.setPageCount(pageData.getTotalPages());
		page.setList(pageData.getContent());
		page.setTotal(pageData.getTotalElements());
		return page;
	}
	
	public org.springframework.data.domain.Page<E> pageEnitry(Integer pageNum, Integer pageSize, T param) {
		PageRequest pageRequest = PageRequest.of(pageNum-1, pageSize);
		Specification<E> where = this.getWhere(param);
		org.springframework.data.domain.Page<E> page = simpleJpaRepository.findAll(where,pageRequest);
		return page;
	}
	/**
	 * 查询方法
	 * @param id
	 * @return
	 */
	@SneakyThrows
	public T get(ID id) {
		 T dto = this.getTClass().getDeclaredConstructor().newInstance();
		 E entity = simpleJpaRepository.findById(id).orElseThrow(() ->{
			return new DuoException(ErrorCode.NOT_FIND);
		});
		BeanUtils.copyProperties(entity, dto);
		return dto;
	}
	/**
	 * 查询方法
	 * @param id
	 * @return
	 */
	@Transactional
	@SuppressWarnings({ "unchecked", "null" })
	@SneakyThrows
	public E create(T dto) {
		 E entity = this.getEClass().getDeclaredConstructor().newInstance();
		 BeanUtils.copyProperties(dto, entity);
		 return simpleJpaRepository.save(entity);
	}
	/**
	 * 更新方法
	 * @param id
	 * @return
	 */
	@Transactional
	public void update(T dto,ID id) {
		E entity = simpleJpaRepository.findById(id).orElseThrow(() ->{
			return new DuoException(ErrorCode.NOT_FIND);
		});
		 BeanUtils.copyProperties(dto, entity);
		 simpleJpaRepository.save(entity);
	}
	/**
	 * 删除
	 * @param id
	 * @return
	 */
	@Transactional
	public void delete(ID id) {
		simpleJpaRepository.deleteById(id);
	}
}
